package cn.xydpeng.springframework.beans.factory.support;

import cn.xydpeng.springframework.beans.factory.DisposableBean;
import cn.xydpeng.springframework.beans.factory.ObjectFactory;
import cn.xydpeng.springframework.beans.factory.config.SingletonBeanRegistry;
import cn.xydpeng.springframework.lang.Nullable;
import cn.xydpeng.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/12
 * @description:
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    private static Logger logger = LoggerFactory.getLogger(DefaultSingletonBeanRegistry.class);

    /** Cache of singleton objects: bean name to bean instance.--- 一级缓存，存放已经初始化完毕的bean */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of early singleton objects: bean name to bean instance. 二级缓存，存放保存实例化完成但未初始化完毕的bean */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    /** Cache of singleton factories: bean name to ObjectFactory. 三级缓存，用于保存 bean创建工厂ObjectFactory，以便后面有机会创建代理对象，此ObjectFactory与FactoryBean毫无关系 */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Set of registered singletons, containing the bean names in registration order. --- 已注册的bean名称 */
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    /** Names of beans that are currently in creation. --- 并发控制，标记bean正在创建中 */
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /** Disposable bean instances: bean name to disposable instance. */
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        addSingleton(beanName,singletonObject);
    }

    protected void addSingleton(String beanName, Object singletonObject){
        singletonObjects.put(beanName,singletonObject);
    }

    @Override
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    /**
     * Return the (raw) singleton object registered under the given name.
     * <p>Checks already instantiated singletons and also allows for an early
     * reference to a currently created singleton (resolving a circular reference).
     * @param beanName the name of the bean to look for
     * @param allowEarlyReference whether early references should be created or not
     * @return the registered singleton object, or {@code null} if none found
     *
     * --- 此为单例bean三级缓存核心逻辑: 解决循环依赖
     */
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // Consistent creation of early reference within full singleton lock
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            //三级缓存中取出，放入二级缓存中
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

    /**
     * Return the (raw) singleton object registered under the given name,
     * creating and registering a new one if none registered yet.
     * @param beanName the name of the bean
     * @param singletonFactory the ObjectFactory to lazily create the singleton
     * with, if necessary
     * @return the registered singleton object
     */
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {

                //beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }catch (Exception ex){

                }finally {
                    //afterSingletonCreation(beanName);
                }
                //加入到一级缓存this.singletonObjects，并清除二三级缓存
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }


    }

    /**
     * Add the given singleton factory for building the specified singleton
     * if necessary.  --- 加入第三级缓存
     * <p>To be called for eager registration of singletons, e.g. to be able to
     * resolve circular references.
     * @param beanName the name of the bean
     * @param singletonFactory the factory for the singleton object
     */
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }


    /**
     * Return whether the specified singleton bean is currently in creation
     * (within the entire factory).
     * @param beanName the name of the bean
     */
    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }


    /**
     * 注册实现了 DisposableBean 接口的 Bean 对象
     * @param beanName
     * @param bean
     */
    public void registerDisposableBean(String beanName, DisposableBean bean) {
        synchronized (this.disposableBeans) {
            this.disposableBeans.put(beanName, bean);
        }
    }

    @Override
    public boolean containsSingleton(String beanName) {
        return this.singletonObjects.containsKey(beanName);
    }

    /**
     * 调用bean的destroy方法
     */
    public void destroySingletons() {
        disposableBeans.forEach((beanName, bean)->{
            try {
                ((DisposableBean) bean).destroy();
            }catch (Exception ex) {
                logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
            }
        });
    }

    @Override
    public final Object getSingletonMutex() {
        return this.singletonObjects;
    }

}
